#pragma once

#include <cstdint>
#include <exception>
#include <iostream>
#include <unordered_map>
#include <vector>

#include "mockturtle/mockturtle.hpp"

template<class TT>
bool bottom_xor_decomposition( const TT& tt, uint32_t var_index1, uint32_t var_index2, TT* func = nullptr )
{
  static_assert( kitty::is_complete_truth_table<TT>::value, "Can only be applied on complete truth tables." );
  const auto co0_var1 = cofactor0( tt, var_index1 );
  const auto co1_var1 = cofactor1( tt, var_index1 );
  const auto dif_var1 = kitty::binary_xor( co0_var1, co1_var1 );

  const auto co0_var2 = cofactor0( tt, var_index2 );
  const auto co1_var2 = cofactor1( tt, var_index2 );
  const auto dif_var2 = kitty::binary_xor( co0_var2, co1_var2 );

  const auto co11 = cofactor1( cofactor1( tt, var_index1 ), var_index2 );
  const auto co00 = cofactor0( cofactor0( tt, var_index1 ), var_index2 );
  const auto co01 = cofactor1( cofactor0( tt, var_index1 ), var_index2 );
  const auto co10 = cofactor0( cofactor1( tt, var_index1 ), var_index2 );

  // if ( equal( co11, co00 ) && equal( co01, co10 ) )
  // {
  //   if ( func )
  //   {
  //     *func = kitty::mux_var( var_index1, co01, co00 );
  //   }
  //   return true;
  // }

  if ( equal( dif_var1, dif_var2 ) )
  {

    if ( func )
    {
      kitty::dynamic_truth_table tt_1(dif_var1.num_vars());
      *func = kitty::binary_xor( kitty::mux_var( var_index1, dif_var1, tt_1 ), co00 );
    }
    return true;
  }

  return false;
}